using Microsoft.KernelMemory;
using AiPlatformAdmin.Api.Data;
using Microsoft.EntityFrameworkCore;
using KMDocument = Microsoft.KernelMemory.Document;
using AppDocument = AiPlatformAdmin.Api.Models.Document;

namespace AiPlatformAdmin.Api.Services;

public class DocumentProcessingService
{
    private readonly IKernelMemory? _memory;
    private readonly AppDbContext _context;
    private readonly ILogger<DocumentProcessingService> _logger;

    public DocumentProcessingService(
        AppDbContext context,
        ILogger<DocumentProcessingService> logger,
        IKernelMemory? memory = null)
    {
        _memory = memory;
        _context = context;
        _logger = logger;
    }

    public async Task<AppDocument> ProcessDocumentAsync(
        int knowledgeBaseId,
        string fileName,
        Stream fileStream,
        string chunkingMode,
        int? chunkSize,
        int? chunkOverlap,
        string? fileType)
    {
        try
        {
            // Get knowledge base info
            var knowledgeBase = await _context.KnowledgeBases
                .FirstOrDefaultAsync(kb => kb.Id == knowledgeBaseId);

            if (knowledgeBase == null)
            {
                throw new ArgumentException($"Knowledge base with ID {knowledgeBaseId} not found");
            }

            // Save file to local storage first
            var uploadsFolder = Path.Combine(Directory.GetCurrentDirectory(), "uploads", knowledgeBaseId.ToString());
            Directory.CreateDirectory(uploadsFolder);

            var filePath = Path.Combine(uploadsFolder, fileName);
            using (var fileStreamWriter = new FileStream(filePath, FileMode.Create))
            {
                await fileStream.CopyToAsync(fileStreamWriter);
            }

            // Get file size
            var fileInfo = new FileInfo(filePath);
            var fileSize = fileInfo.Length;

            // Create document record
            var document = new AppDocument
            {
                KnowledgeBaseId = knowledgeBaseId,
                FileName = fileName,
                FilePath = filePath,
                FileSize = fileSize,
                FileType = fileType,
                ChunkingMode = chunkingMode,
                ChunkSize = chunkSize,
                ChunkOverlap = chunkOverlap,
                UploadedAt = DateTime.UtcNow,
                UpdatedAt = DateTime.UtcNow
            };

            _context.Documents.Add(document);
            await _context.SaveChangesAsync();

            // Import document to KernelMemory with configured chunking
            var documentId = $"kb_{knowledgeBaseId}_doc_{document.Id}";

            if (_memory != null)
            {
                _logger.LogInformation(
                    "Starting vectorization for document {DocumentId}, mode: {ChunkingMode}",
                    documentId,
                    chunkingMode);

                // Configure chunking based on mode
                var tags = new TagCollection
                {
                    { "knowledge_base_id", knowledgeBaseId.ToString() },
                    { "document_id", document.Id.ToString() },
                    { "chunking_mode", chunkingMode }
                };

                // Import document into KernelMemory
                // The chunking parameters are handled by KernelMemory configuration
                await _memory.ImportDocumentAsync(
                    filePath,
                    documentId: documentId,
                    tags: tags,
                    index: $"kb_{knowledgeBaseId}");

                _logger.LogInformation(
                    "Document {DocumentId} vectorized successfully with {ChunkingMode} mode",
                    documentId,
                    chunkingMode);
            }
            else
            {
                _logger.LogWarning("KernelMemory not configured. Document saved without vectorization.");
            }

            return document;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error processing document: {FileName}", fileName);
            throw;
        }
    }

    public async Task<bool> DeleteDocumentAsync(int documentId)
    {
        try
        {
            var document = await _context.Documents.FindAsync(documentId);
            if (document == null)
            {
                return false;
            }

            // Delete from KernelMemory if configured
            if (_memory != null)
            {
                var kernelMemoryDocId = $"kb_{document.KnowledgeBaseId}_doc_{document.Id}";
                await _memory.DeleteDocumentAsync(
                    documentId: kernelMemoryDocId,
                    index: $"kb_{document.KnowledgeBaseId}");
            }

            // Delete file from storage
            if (File.Exists(document.FilePath))
            {
                File.Delete(document.FilePath);
            }

            // Delete from database
            _context.Documents.Remove(document);
            await _context.SaveChangesAsync();

            _logger.LogInformation("Document {DocumentId} deleted successfully", documentId);
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error deleting document: {DocumentId}", documentId);
            throw;
        }
    }

    public async Task<List<Citation>> SearchDocumentsAsync(
        int knowledgeBaseId,
        string query,
        int limit = 5,
        double minRelevance = 0.0)
    {
        if (_memory == null)
        {
            throw new InvalidOperationException("KernelMemory is not configured. Cannot search documents.");
        }

        try
        {
            var index = $"kb_{knowledgeBaseId}";

            var searchResult = await _memory.SearchAsync(
                query: query,
                index: index,
                limit: limit,
                minRelevance: minRelevance);

            return searchResult.Results.ToList();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error searching documents in knowledge base: {KnowledgeBaseId}", knowledgeBaseId);
            throw;
        }
    }

    public async Task<string> AskAsync(
        int knowledgeBaseId,
        string question,
        double minRelevance = 0.0)
    {
        if (_memory == null)
        {
            throw new InvalidOperationException("KernelMemory is not configured. Cannot ask questions.");
        }

        try
        {
            var index = $"kb_{knowledgeBaseId}";

            var answer = await _memory.AskAsync(
                question: question,
                index: index,
                minRelevance: minRelevance);

            return answer.Result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error asking question to knowledge base: {KnowledgeBaseId}", knowledgeBaseId);
            throw;
        }
    }
}
